#    Supsta
#    Copyright (c) 2014 Sebastian Dufner
#
#    This file is part of Supsta.
#
#    Supsta is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    Supsta is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

require 'supsta/gimp/drawable'
require 'supsta/gimp/layer'
require 'supsta/gimp/selection'

module Supsta
  module Gimp

    ##
    # Class representing a GIMP image.
    #
    # *Note:* Images are deleted (see #delete!) automatically on finalization.

    class Image
      def initialize(application, image)
        @app, @self = application, image

        ObjectSpace.define_finalizer(self, self.method(:delete!).to_proc)
      end

      ##
      # Returns the current scope.

      def scope
        @app
      end

      ##
      # Saves this image to +filename+, using magic to determine the correct
      # file type.
      #
      # :call-seq: save(filename)

      def save(file)
        layer = active_layer
        file = file.gsub(/\\/, '\\\\').gsub(/"/, '\"')
        script = "(gimp-file-save RUN-NONINTERACTIVE #{@self} #{layer} "
        script.concat "\"#{file}\" \"#{file}\")\n"

        @app.script.concat script

        self
      end

      ##
      # Deletes this image.

      def delete!
        return unless @self
        @app.script.concat "(gimp-image-delete #{@self})\n"
        @app = @self = nil

        nil
      end

      ##
      # Returns the active Layer. Returns +self+ if a block is passed, passing
      # the Layer to the block instead.
      #
      # :call-seq:  active_layer()
      #             active_layer() { |layer| ... }

      def active_layer
        var = @app.new_var
        layer = Layer.new(@app, var, self)
        scope.def var, "(car(gimp-image-get-active-layer #{@self}))"

        if block_given?
          yield layer
          self
        else
          layer
        end
      end

      ##
      # Returns the active Drawable. Returns +self+ if a block is passed,
      # passing the Drawable to the block instead.
      #
      # :call-seq:  active_drawable()
      #             active_drawable() { |drawable| ... }

      def active_drawable
        var = @app.new_var
        drawable = Drawable.new(@app, var, self)
        scope.def var, "(car(gimp-image-get-active-drawable #{@self}))"

        if block_given?
          yield drawable
          self
        else
          drawable
        end
      end

      ##
      # Returns a new Selection object. Returns +self+ if a block is passed,
      # passing the Selection to the block instead.
      #
      # :call-seq:  select()
      #             select() { |select| ... }

      def select
        selection = Selection.new(@app, self)

        if block_given?
          yield selection
          self
        else
          selection
        end
      end

      ##
      # Converts this Image's #type to RGB.

      def convert_rgb
        script = "(if (not (= 0 (car (gimp-image-base-type #{@self})))) "
        script.concat "(gimp-image-convert-rgb #{@self}))\n"

        @app.script.concat script

        self
      end

      ##
      # Merges all visible Layers and returns the newly created Layer. Returns
      # +self+ if a block is passed, passing the Layer to the block instead.
      #
      # :call-seq:  merge_visible_layers()
      #             merge_visible_layers() { |layer| ... }

      def merge_visible_layers
        var = @app.new_var
        layer = Layer.new(@app, var, self)
        scope.def var, "(car(gimp-image-merge-visible-layers #{@self} 1))"

        if block_given?
          yield layer
          self
        else
          layer
        end
      end

      ##
      # Resizes this image to dimensions +width+ and +height+, using offsets
      # +x+ and +y+.
      #
      # :call-seq: resize(width, height, x = 0, y = 0)

      def resize(width, height, offset_x = 0, offset_y = 0)
        @app.script.concat "(gimp-image-resize #{@image} #{width} #{height} #{offset_x} #{offset_y})\n"

        self
      end

      ##
      # Sets the specified component's state to +:active+ or +:inactive+.
      # Component values +:red+, +:green+, +:blue+, +:gray+, +:indexed+ and
      # +:alpha+ are supported.

      def set_component_state(component, state = :active)
        component = case component
          when :red     then 0
          when :green   then 1
          when :blue    then 2
          when :gray    then 3
          when :indexed then 4
          when :alpha   then 5
          else fail ArgumentError, "unknown component: #{component}"
        end
        state = state == :active ? 1 : 0

        script = "(gimp-image-set-component-active #{@self} #{component} "
        script.concat "#{state})\n"

        @app.script.concat script

        self
      end

      ##
      # Set the color profile to RGB.

      def set_profile_rgb
        @app.script.concat "(plug-in-icc-profile-set-rgb 0 #{@self})\n"

        self
      end

      ##
      # Returns this image's variable name.

      def to_s
        @self.to_s
      end

      ##
      # Returns this Image's height.

      def height
        var = @app.new_var
        scope.def var, "(car (gimp-image-height #{@self}))"

        Integer.new(var)
      end

      ##
      # Returns this Image's width.

      def width
        var = @app.new_var
        scope.def var, "(car (gimp-image-width #{@self}))"

        Integer.new(var)
      end

    end
  end
end
